package com.sc.nft.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sc.nft.dao.*;
import com.sc.nft.dto.profit.BusinessShareProfitDTO;
import com.sc.nft.dto.profit.MetaShareProfitDTO;
import com.sc.nft.dto.profit.SaveShareProfitDTO;
import com.sc.nft.entity.*;
import com.sc.nft.enums.AllocationTypeEnum;
import com.sc.nft.enums.DivideTypeEnum;
import com.sc.nft.enums.MarketLevelEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.ShareProfitService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

/**
 * 服务接口实现
 *
 * @author zxy
 * @since 2023-12-06 16:05:42
 * @description 商户banner
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ShareProfitServiceImpl implements ShareProfitService {
    private final ShareProfitDao shareProfitDao;
    private final ShareProfitDirectCollectionDao shareProfitDirectCollectionDao;
    private final ShareProfitPanelDao shareProfitPanelDao;
    private final ShareProfitRatioDao shareProfitRatioDao;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final DigitalCollectionDao digitalCollectionDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProfit(SaveShareProfitDTO dto) {
        check(dto);
        ShareProfitPanel panel = null;
        if (ObjectUtil.isNotNull(dto.getId())) {
            panel = shareProfitPanelDao.getById(dto.getId());
            Assert.notNull(panel, () -> new GlobalRunTimeException("未找到原模板"));
            shareProfitDao.clearByPanelId(panel.getId());
            shareProfitDirectCollectionDao.clearByPanelId(panel.getId());
            shareProfitRatioDao.clearByPanelId(panel.getId());
        } else {
            panel = new ShareProfitPanel();
            panel.setStatus(false);
        }
        panel.setMarketLevel(dto.getMarketLevel());
        panel.setPanelName(dto.getPanelName());
        panel.insertOrUpdate();

        for (Long collectionId : dto.getCollectionIds()) {
            ShareProfitDirectCollection shareProfitDirectCollection = new ShareProfitDirectCollection();
            shareProfitDirectCollection.setPanelId(panel.getId());
            shareProfitDirectCollection.setCollectionId(collectionId);
            shareProfitDirectCollection.insert();
        }

        //直推
        ShareProfit directPush = new ShareProfit();
        directPush.setPanelId(panel.getId());
        directPush.setDivideType(DivideTypeEnum.DIRECT_PUSH);
        directPush.setSumRatio(dto.getDirectPushRatio());
        directPush.insert();
        //版图省级比例
        ShareProfit metaMapProvince = new ShareProfit();
        metaMapProvince.setPanelId(panel.getId());
        metaMapProvince.setDivideType(DivideTypeEnum.MATE_MAP_PROVINCE);
        metaMapProvince.setSumRatio(dto.getMetaMapProvinceRatio());
        metaMapProvince.insert();
        //版图市级比例
        ShareProfit metaMapCity = new ShareProfit();
        metaMapCity.setPanelId(panel.getId());
        metaMapCity.setDivideType(DivideTypeEnum.MATE_MAP_CITY);
        metaMapCity.setSumRatio(dto.getMetaMapCityRatio());
        metaMapCity.insert();
        //版图区级比例
        ShareProfit metaMapRegion = new ShareProfit();
        metaMapRegion.setPanelId(panel.getId());
        metaMapRegion.setDivideType(DivideTypeEnum.MATE_MAP_REGION);
        metaMapRegion.setSumRatio(dto.getMetaMapRegionRatio());
        metaMapRegion.insert();
        //玛特分润
        ShareProfit metaProfit = new ShareProfit();
        metaProfit.setPanelId(panel.getId());
        metaProfit.setDivideType(DivideTypeEnum.DAO);
        metaProfit.setSumRatio(dto.getMetaShareProfitDTO().getRatio());
        metaProfit.setDaoId(6L);
        metaProfit.insert();
        //分红池
        ShareProfitRatio boundsPoolRatio = new ShareProfitRatio();
        boundsPoolRatio.setPanelId(panel.getId());
        boundsPoolRatio.setProfitId(metaProfit.getId());
        boundsPoolRatio.setAllocationPoolType(AllocationTypeEnum.BOUNDS_POOL);
        boundsPoolRatio.setShareRatio(dto.getMetaShareProfitDTO().getBoundsPoolRatio());
        boundsPoolRatio.insert();
        //商务
        ShareProfitRatio businessRatio = new ShareProfitRatio();
        businessRatio.setPanelId(panel.getId());
        businessRatio.setProfitId(metaProfit.getId());
        businessRatio.setAllocationPoolType(AllocationTypeEnum.BUSINESS);
        businessRatio.setShareRatio(dto.getMetaShareProfitDTO().getBusinessRatio());
        businessRatio.insert();

        //项目
        ShareProfitRatio projectRatio = new ShareProfitRatio();
        projectRatio.setPanelId(panel.getId());
        projectRatio.setProfitId(metaProfit.getId());
        projectRatio.setAllocationPoolType(AllocationTypeEnum.PROJECT);
        projectRatio.setShareRatio(dto.getMetaShareProfitDTO().getProjectRatio());
        projectRatio.insert();

        //公司
        ShareProfitRatio companyRatio = new ShareProfitRatio();
        companyRatio.setPanelId(panel.getId());
        companyRatio.setProfitId(metaProfit.getId());
        companyRatio.setAllocationPoolType(AllocationTypeEnum.COMPANY);
        companyRatio.setShareRatio(dto.getMetaShareProfitDTO().getCompanyRatio());
        companyRatio.insert();
        //企业分润
        for (BusinessShareProfitDTO businessShareProfitDTO : dto.getBusinessShareProfitDTOS()) {
            ShareProfit businessProfit = new ShareProfit();
            businessProfit.setPanelId(panel.getId());
            businessProfit.setDivideType(DivideTypeEnum.DAO);
            businessProfit.setSumRatio(businessShareProfitDTO.getRatio());
            businessProfit.setDaoId(businessShareProfitDTO.getDaoId());
            businessProfit.insert();
            //分红池
            boundsPoolRatio = new ShareProfitRatio();
            boundsPoolRatio.setPanelId(panel.getId());
            boundsPoolRatio.setProfitId(businessProfit.getId());
            boundsPoolRatio.setAllocationPoolType(AllocationTypeEnum.BOUNDS_POOL);
            boundsPoolRatio.setShareRatio(businessShareProfitDTO.getBoundsPoolRatio());
            boundsPoolRatio.insert();
            //公司
            companyRatio = new ShareProfitRatio();
            companyRatio.setPanelId(panel.getId());
            companyRatio.setProfitId(businessProfit.getId());
            companyRatio.setAllocationPoolType(AllocationTypeEnum.COMPANY);
            companyRatio.setShareRatio(businessShareProfitDTO.getCompanyRatio());
            companyRatio.insert();
            //礼包收入
            companyRatio = new ShareProfitRatio();
            companyRatio.setPanelId(panel.getId());
            companyRatio.setProfitId(businessProfit.getId());
            companyRatio.setAllocationPoolType(AllocationTypeEnum.GIFT);
            companyRatio.setShareRatio(businessShareProfitDTO.getGiftRatio());
            companyRatio.insert();
        }


    }

    @Override
    public SaveShareProfitDTO getProfit(Long id) {
        ShareProfitPanel panel = shareProfitPanelDao.getById(id);
        Assert.notNull(panel, () -> new GlobalRunTimeException("未找到模板"));
        SaveShareProfitDTO saveShareProfitDTO = new SaveShareProfitDTO();
        saveShareProfitDTO.setMarketLevel(panel.getMarketLevel());
        saveShareProfitDTO.setId(panel.getId());
        saveShareProfitDTO.setPanelName(panel.getPanelName());
        saveShareProfitDTO.setCollectionIds(shareProfitDirectCollectionDao.getCollectionIdsByPanelId(id));
        List<ShareProfit> shareProfitList = shareProfitDao.getByPanelId(id);
        if (CollUtil.isNotEmpty(shareProfitList)) {
            List<BusinessShareProfitDTO> businessShareProfitDTOS = Lists.newArrayList();
            for (ShareProfit collectionShareProfit : shareProfitList) {
                switch (collectionShareProfit.getDivideType()) {
                    case MATE_MAP_REGION:
                        saveShareProfitDTO.setMetaMapRegionRatio(collectionShareProfit.getSumRatio());
                        break;
                    case MATE_MAP_CITY:
                        saveShareProfitDTO.setMetaMapCityRatio(collectionShareProfit.getSumRatio());
                        break;
                    case MATE_MAP_PROVINCE:
                        saveShareProfitDTO.setMetaMapProvinceRatio(collectionShareProfit.getSumRatio());
                        break;
                    case DIRECT_PUSH:
                        saveShareProfitDTO.setDirectPushRatio(collectionShareProfit.getSumRatio());
                        break;
                    case DAO:
                        if (collectionShareProfit.getDaoId() == 6L) {
                            MetaShareProfitDTO metaShareProfitDTO = new MetaShareProfitDTO();
                            metaShareProfitDTO.setRatio(collectionShareProfit.getSumRatio());
                            List<ShareProfitRatio> shareProfitRatios = shareProfitRatioDao.getProfitId(collectionShareProfit.getId());
                            for (ShareProfitRatio shareProfitRatio : shareProfitRatios) {
                                switch (shareProfitRatio.getAllocationPoolType()) {
                                    case BOUNDS_POOL:
                                        metaShareProfitDTO.setBoundsPoolRatio(shareProfitRatio.getShareRatio());
                                        break;
                                    case BUSINESS:
                                        metaShareProfitDTO.setBusinessRatio(shareProfitRatio.getShareRatio());
                                        break;
                                    case PROJECT:
                                        metaShareProfitDTO.setProjectRatio(shareProfitRatio.getShareRatio());
                                        break;
                                    case COMPANY:
                                        metaShareProfitDTO.setCompanyRatio(shareProfitRatio.getShareRatio());
                                        break;
                                }
                            }
                            saveShareProfitDTO.setMetaShareProfitDTO(metaShareProfitDTO);
                        } else {
                            BusinessShareProfitDTO businessShareProfitDTO = new BusinessShareProfitDTO();
                            businessShareProfitDTO.setDaoId(collectionShareProfit.getDaoId());
                            businessShareProfitDTO.setRatio(collectionShareProfit.getSumRatio());
                            List<ShareProfitRatio> shareProfitRatios = shareProfitRatioDao.getProfitId(collectionShareProfit.getId());
                            for (ShareProfitRatio shareProfitRatio : shareProfitRatios) {
                                switch (shareProfitRatio.getAllocationPoolType()) {
                                    case BOUNDS_POOL:
                                        businessShareProfitDTO.setBoundsPoolRatio(shareProfitRatio.getShareRatio());
                                        break;
                                    case COMPANY:
                                        businessShareProfitDTO.setCompanyRatio(shareProfitRatio.getShareRatio());
                                        break;
                                    case GIFT:
                                        businessShareProfitDTO.setGiftRatio(shareProfitRatio.getShareRatio());
                                        break;
                                }
                            }
                            businessShareProfitDTOS.add(businessShareProfitDTO);
                        }
                        break;
                }
            }
            saveShareProfitDTO.setBusinessShareProfitDTOS(businessShareProfitDTOS);
        } else {
            saveShareProfitDTO.setDirectPushRatio(BigDecimal.ZERO);
            MetaShareProfitDTO metaShareProfitDTO = new MetaShareProfitDTO();
            metaShareProfitDTO.setRatio(BigDecimal.TEN.multiply(BigDecimal.TEN));
            metaShareProfitDTO.setBoundsPoolRatio(BigDecimal.ZERO);
            metaShareProfitDTO.setBusinessRatio(BigDecimal.ZERO);
            metaShareProfitDTO.setProjectRatio(BigDecimal.ZERO);
            metaShareProfitDTO.setCompanyRatio(metaShareProfitDTO.getRatio());
            saveShareProfitDTO.setMetaShareProfitDTO(metaShareProfitDTO);
            saveShareProfitDTO.setBusinessShareProfitDTOS(Lists.newArrayList());

        }
        return saveShareProfitDTO;
    }


    private void check(SaveShareProfitDTO dto) {
        ShareProfitPanel panel = shareProfitPanelDao.getByPanelName(dto.getPanelName());
        if (ObjectUtil.isAllNotEmpty(panel, dto.getId())) {
            Assert.isTrue(panel.getId().longValue() == dto.getId().longValue(), () -> new GlobalRunTimeException("存在同名模板，请修改模板名称！"));
        } else {
            Assert.isNull(panel, () -> new GlobalRunTimeException("存在同名模板，请修改模板名称！"));
        }

        List<BusinessShareProfitDTO> businessShareProfits = dto.getBusinessShareProfitDTOS();
        if (dto.getMarketLevel() == MarketLevelEnum.TRANS_POOL) {//如果是交易池 把直推版图设置为0 防止进行分润
            dto.setDirectPushRatio(new BigDecimal(0));
            dto.setMetaMapProvinceRatio(new BigDecimal(0));
            dto.setMetaMapCityRatio(new BigDecimal(0));
            dto.setMetaMapRegionRatio(new BigDecimal(0));
        } else {
            BigDecimal sumRatio = dto.getDirectPushRatio().add(dto.getMetaMapProvinceRatio()).add(dto.getMetaMapCityRatio()).add(dto.getMetaMapRegionRatio()).add(dto.getMetaShareProfitDTO().getRatio());
            if (CollUtil.isNotEmpty(dto.getBusinessShareProfitDTOS())) {
                sumRatio = sumRatio.add(dto.getBusinessShareProfitDTOS().stream().map(BusinessShareProfitDTO::getRatio).reduce(BigDecimal::add).get());
            }
            Assert.isTrue(NumberUtil.equals(sumRatio, BigDecimal.ONE), () -> new GlobalRunTimeException("总分润比例合计不等于100%"));
            BigDecimal metaRatio = dto.getMetaShareProfitDTO().getBusinessRatio().add(dto.getMetaShareProfitDTO().getCompanyRatio()).add(dto.getMetaShareProfitDTO().getProjectRatio()).add(dto.getMetaShareProfitDTO().getBoundsPoolRatio());
            Assert.isTrue(NumberUtil.equals(metaRatio, BigDecimal.ONE), () -> new GlobalRunTimeException("玛特分配合计不等于100%"));
        }

        for (BusinessShareProfitDTO businessShareProfitDTO : businessShareProfits) {
            UserCreatorInfo userCreatorInfo = userCreatorInfoDao.getById(businessShareProfitDTO.getDaoId());
            Assert.notNull(userCreatorInfo, () -> new GlobalRunTimeException("该品牌不存在"));
            
            Assert.notNull(userCreatorInfo.getStatus() == 0, () -> new GlobalRunTimeException("该品牌不是DAO"));
            BigDecimal ratio = businessShareProfitDTO.getCompanyRatio().add(businessShareProfitDTO.getBoundsPoolRatio()).add(businessShareProfitDTO.getGiftRatio());
            Assert.isTrue(NumberUtil.equals(ratio, BigDecimal.ONE), () -> new GlobalRunTimeException(userCreatorInfo.getDaoName() + "分配合计不等于100%"));
        }
        if (CollUtil.isNotEmpty(dto.getCollectionIds()) && digitalCollectionDao.getByIds(dto.getCollectionIds()).size() != dto.getCollectionIds().size()) {
            throw new GlobalRunTimeException("直推关联藏品中包含不存在的藏品");
        }

    }
}